package jehc.cloud.iot.live.common.service.impl;

import jehc.cloud.common.base.BaseResult;
import jehc.cloud.common.util.StringUtil;
import jehc.cloud.iot.live.common.timer.AutoKillTask;
import jehc.cloud.iot.live.common.timer.AutoKillTranscribeTask;
import jehc.cloud.iot.live.common.util.CacheUtil;
import jehc.cloud.iot.live.common.util.IpUtil;
import jehc.cloud.iot.live.common.util.ScreenShotUtil;
import jehc.cloud.iot.live.common.worker.FlexPusher;
import jehc.cloud.iot.live.common.worker.TranscribePusher;
import jehc.cloud.iot.live.common.service.LiveService;
import jehc.cloud.iot.live.model.CameraEntity;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
 * @Desc 视频直播流
 * @Author 邓纯杰
 * @CreateTime 2012-12-12 12:12:12
 */
@Service
@Slf4j
@Data
public class LiveServiceImpl implements LiveService {
    @Value("${jehc.stream.nginx.ip}")
    private String streamIp;//配置定义地址
    @Value("${jehc.stream.nginx.tcp.port}")
    private String streamTcpPort;
    @Value("${jehc.stream.nginx.httpPort}")
    private String httpPort;
    @Value("${jehc.stream.ipExtra}")
    private String ipExtra;//推送额外地址
    @Autowired
    AutoKillTask autoKillTask;//直播，回放终止器
    @Autowired
    AutoKillTranscribeTask autoKillTranscribeTask;//录制视频终止器
    @Autowired
    ScreenShotUtil screenShotUtil;//截图工具类
    /**
     * 实时预览
     * @param cameraEntity
     * @return
     */
    public BaseResult live(CameraEntity cameraEntity){
        BaseResult result = new BaseResult();
        result.setMessage("播放成功！");
        if (!StringUtils.isEmpty(cameraEntity.getIp()) && !StringUtils.isEmpty(cameraEntity.getUsername()) && !StringUtils.isEmpty(cameraEntity.getPassword()) && !StringUtils.isEmpty(cameraEntity.getChannel())) {
            CameraEntity cameraEntityCache = CacheUtil.STREAMMAP.get(cameraEntity.getStream());
            if(null == cameraEntityCache){//首次推流
                // 开始推流
                cameraEntity = openStream(cameraEntity);
                result.setData(cameraEntity.getUrl());
                log.info("打开：" + cameraEntity.getRtsp());
                result.setData(cameraEntity);
                return result;
            }
            if(null == cameraEntity.getStartTime()){ //直播流
                cameraEntity = cameraEntityCache;
                log.info("通过已播放通道中直接打开：" + cameraEntity.getRtsp()+",当前错误信息："+cameraEntity.getErrorCount());
            }else{//回放流
                if(cameraEntity.getReStart()){//如果执行重播则删除缓存中历史并终止其线程（支持每一个客户端重置并且不影响其它客户端播放）
                    autoKillTask.killTask(cameraEntity.getStream());
                    try {
                        while (true){
                            if(null == CacheUtil.STREAMMAP.get(cameraEntity.getStream())){
                                cameraEntity = openStream(cameraEntity);//重新执行新的线程
                                log.info(cameraEntity.getRtsp() + " 重新开启回放...");
                                break;
                            }
                            Thread.sleep(500);
                        }
                    }catch (Exception e){

                    }
                }else{
                    cameraEntity = cameraEntityCache;
                    log.info(cameraEntity.getRtsp() + " 开启回放...");
                }
            }
            result.setData(cameraEntity);
        }else{
            result.setMessage("播放失败，未能获取到摄像头参数！");
            result.setStatus(500);
        }
        return result;
    }


    /**
     * 推流器
     * @param cameraEntity
     * @return
     */
    private CameraEntity openStream(CameraEntity cameraEntity) {
        // 生成token
        String token = cameraEntity.getStream();
        String rtsp = "";
        String rtmp = "";
        String ip = IpUtil.IpConvert(cameraEntity.getIp());
        String url = "";
        int port = cameraEntity.getPort()==null?554:cameraEntity.getPort();
        if (null != cameraEntity.getStartTime()) {//回放（此时的用户名和IP及端口都是NVR存储设备）
            String startTime=formatPullTime(cameraEntity.getStartTime(),true);
            if (null != cameraEntity.getEndTime()) {
                if(cameraEntity.getType().equals("0")){//海康
                    String endTime = formatPullTime(cameraEntity.getEndTime(),false);
                    rtsp = "rtsp://" + cameraEntity.getUsername() + ":" + cameraEntity.getPassword() + "@" + ip + ":"+port+"/Streaming/tracks/" + cameraEntity.getChannel() + "?starttime=" + startTime+ "&endtime=" + endTime;
                }else if(cameraEntity.getType().equals("1")){//大华
                    startTime=formatTime(cameraEntity.getStartTime());
                    String endTime = formatTime(cameraEntity.getEndTime());
                    rtsp = "rtsp://" + cameraEntity.getUsername() + ":" + cameraEntity.getPassword() + "@" + ip + ":"+port+"/cam/playback?channel="+cameraEntity.getChannel()+"&subtype=0&starttime="+ startTime+ "&endtime=" +endTime;
                }
            } else {
                if(cameraEntity.getType().equals("0")){//海康
                    String endTime = formatPullTime(new Date(),false);
                    rtsp = "rtsp://" + cameraEntity.getUsername() + ":" + cameraEntity.getPassword() + "@" + ip + ":"+port+"/Streaming/tracks/" + cameraEntity.getChannel() + "?starttime=" + startTime+ "&endtime=" +endTime;
                }else if(cameraEntity.getType().equals("1")){//大华
                    startTime=formatTime(cameraEntity.getStartTime());
                    String endTime = formatTime(new Date());
                    rtsp = "rtsp://" + cameraEntity.getUsername() + ":" + cameraEntity.getPassword() + "@" + ip + ":"+port+"/cam/playback?channel="+cameraEntity.getChannel()+"&subtype=0&starttime="+ startTime+ "&endtime=" +endTime;
                }
            }
            rtmp = "rtmp://" + IpUtil.IpConvert(this.streamIp) + ":" + this.streamTcpPort + "/live/" +token;
            if (this.ipExtra.equals("127.0.0.1")) {
                url = rtmp;
            } else {
                url = "rtmp://" + IpUtil.IpConvert(this.ipExtra) + ":" + this.streamTcpPort + "/live/"+ token;
            }
        } else {// 直播流
            if(cameraEntity.getType().equals("0")){//海康
                String subType = "sub";
                if( 0== cameraEntity.getSubtype()){
                    subType = "main";
                }
                rtsp = "rtsp://" + cameraEntity.getUsername() + ":" + cameraEntity.getPassword() + "@" + ip + ":"+port+"/h264/" + cameraEntity.getStream()+"/"+subType + "/av_stream";//海康取码
               /* rtsp = "rtsp://" + cameraEntity.getUsername() + ":" + cameraEntity.getPassword() + "@" + ip + ":"+port+"/h264/" + cameraEntity.getChannel() + "/" + cameraEntity.getStream() + "/av_stream";//海康取码*/
            }else if(cameraEntity.getType().equals("1")){//大华
                rtsp = "rtsp://" + cameraEntity.getUsername() + ":" + cameraEntity.getPassword() + "@" + ip + ":"+port+"/cam/realmonitor?channel=" + cameraEntity.getChannel() + "&subtype="+cameraEntity.getSubtype();//大华取码0主码流1子码流2辅码流
                /*rtsp = "rtsp://" + cameraEntity.getUsername() + ":" + cameraEntity.getPassword() + "@" + ip + ":"+port+"/cam/realmonitor?channel=" + cameraEntity.getChannel() + "&subtype=0";//大华取码*/
            }else if(cameraEntity.getType().equals("2")){//宇视
                rtsp =  "rtsp://" + cameraEntity.getUsername() + ":" + cameraEntity.getPassword() + "@" + ip + ":"+port+"/video2";//宇视取码
            }
            rtmp = "rtmp://" + IpUtil.IpConvert(this.streamIp) + ":" + this.streamTcpPort + "/live/" + token;
            if (this.ipExtra.equals("127.0.0.1")) {
                url = rtmp;
            } else {
                url = "rtmp://" + IpUtil.IpConvert(this.ipExtra) + ":" + this.streamTcpPort + "/live/" + token;
            }
        }
        String httpUrl = "http://" + IpUtil.IpConvert(this.streamIp) + ":"+this.httpPort +"/live?port=" + this.streamTcpPort + "&app=live&stream=" + token;//增强Http流
        cameraEntity.setRtsp(rtsp);
        cameraEntity.setRtmp(rtmp);
        cameraEntity.setUrl(url);
        cameraEntity.setHttpURL(httpUrl);
        cameraEntity.setCount(cameraEntity.getCount() == null ?1:cameraEntity.getCount());
        cameraEntity.setToken(token);
        FlexPusher.MyRunnable job = new FlexPusher.MyRunnable(cameraEntity);// 执行任务
        if(null ==  CacheUtil.jobMap.get(token)){//线程不存在放入（一个客户端设备只保证一个活的线程）
            FlexPusher.MyRunnable.es.execute(job);
            CacheUtil.jobMap.put(token, job);
        }
        return cameraEntity;
    }

    /**
     * 关闭实时预览（暂时不生效）
     * @param cameraEntity
     * @return
     */
    public BaseResult stopLive(CameraEntity cameraEntity){
        BaseResult result = new BaseResult();
        if (!StringUtils.isEmpty(cameraEntity.getStream())) {
            if (CacheUtil.jobMap.containsKey(cameraEntity.getStream()) && CacheUtil.STREAMMAP.containsKey(cameraEntity.getStream())) {
                if (0 < CacheUtil.STREAMMAP.get(cameraEntity.getStream()).getCount()) {
                    // 人数-1
                    CacheUtil.STREAMMAP.get(cameraEntity.getStream()).setCount(CacheUtil.STREAMMAP.get(cameraEntity.getStream()).getCount() - 1);
                    log.info("关闭：" + CacheUtil.STREAMMAP.get(cameraEntity.getStream()).getRtsp() + ";当前使用人数为：" + CacheUtil.STREAMMAP.get(cameraEntity.getStream()).getCount());
                }
            }
        }
        return result;
    }

    /**
     * 构造监控回放查询字段
     * @param date
     * @param start
     * @return
     */
    private String formatPullTime(Date date, boolean start){
        Calendar calendar = Calendar.getInstance();
        if (date != null) {
            calendar.setTime(date);
        }
        if (start) {
            calendar.add(Calendar.SECOND, -10);
        } else {
            calendar.add(Calendar.SECOND, 10);
        }
        //海康威视取回放的时间格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd#HHmmss$");
        String ret = sdf.format(calendar.getTime());
        ret = ret.replace("#", "t");
        ret = ret.replace("$", "z");
        return ret;
    }

    /**
     * 构造监控回放查询字段
     * @param date
     * @return
     */
    private String formatTime(Date date){
        //海康威视取回放的时间格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
        String ret = sdf.format(date);
        return ret;
    }


    /**
     * 录制视频
     * @param cameraEntity
     * @return
     */
    public BaseResult startTranscribe(CameraEntity cameraEntity){
        String token = cameraEntity.getStream();
        cameraEntity.setToken(token);
        BaseResult baseResult = new BaseResult();
        if(StringUtil.isEmpty(cameraEntity.getStream())){
            baseResult.setMessage("未能获取到设备编号！");
            return baseResult;
        }
        if(StringUtil.isEmpty(cameraEntity.getVideoName())){
            baseResult.setMessage("未能获取到录制输出视频名称！");
            return baseResult;
        }
        if(StringUtil.isEmpty(cameraEntity.getVideoType())){
            baseResult.setMessage("未能获取到录制输出视频类型！");
            return baseResult;
        }
        String inputFile = cameraEntity.getRtspUrl(); //-该地址可以是网络直播/录播地址，也可以是远程/本地文件路径
        String outputFile = cameraEntity.getPath()+"/"+cameraEntity.getVideoName()+"."+cameraEntity.getVideoType();// -该地址只能是文件地址，如果使用该方法推送流媒体服务器会报错，原因是没有设置编码格式
        Integer audioChannel = cameraEntity.getAudio();//是否录制音频0:不录制/1:录制
        if(StringUtil.isEmpty(inputFile)){
            log.info("未能获取到视频源地址！");
            return null;
        }
        if(StringUtil.isEmpty(outputFile)){
            log.info("未能获取到录制输出地址！");
            return null;
        }
        if(null == audioChannel){
            log.info("未能获取到录制音频参数！");
            return null;
        }
        TranscribePusher.TranscribePusherRunnable job = new TranscribePusher.TranscribePusherRunnable(cameraEntity);// 执行任务
        if(null ==  CacheUtil.transcribeJobMap.get(cameraEntity.getStream())){//线程不存在放入（一个客户端设备只保证一个活的线程）
            TranscribePusher.TranscribePusherRunnable.es.execute(job);
            cameraEntity.setCount(cameraEntity.getCount()+1);
            CacheUtil.transcribeJobMap.put(cameraEntity.getStream(), job);
        }
        return baseResult;
    }

    /**
     * 停止录制
     * @param cameraEntity
     * @return
     */
    public BaseResult stopTranscribe(CameraEntity cameraEntity){
        BaseResult baseResult = new BaseResult();
        if(StringUtil.isEmpty(cameraEntity.getStream())){
            baseResult.setMessage("未能获取到设备编号！");
            return baseResult;
        }
        autoKillTranscribeTask.killTask(cameraEntity.getStream());
        try {
            while (true){
                if(null == CacheUtil.transcribeMap.get(cameraEntity.getStream())){
                    cameraEntity = openStream(cameraEntity);//重新执行新的线程
                    baseResult.setMessage(cameraEntity.getStream() + " 停止录制成功");
                    log.info(cameraEntity.getStream() + " 停止录制成功...");
                    break;
                }
                Thread.sleep(500);
            }
        }catch (Exception e){
            baseResult.setMessage(cameraEntity.getStream() + " 停止录制失败");
            log.info(cameraEntity.getStream() + " 停止录制失败...");
        }
        return baseResult;
    }

    /**
     * 截图
     * @param cameraEntity
     * @return
     */
    public BaseResult screenShot(CameraEntity cameraEntity){
        BaseResult baseResult = new BaseResult();
        boolean result = screenShotUtil.fetchFrame(cameraEntity);
        if(result){
            baseResult.setMessage("截图成功！");
        }else{
            baseResult.setMessage("截图失败");
        }
        return baseResult;
    }
}
